package com.tierstall.client;

import java.util.Date;
import java.util.HashMap;

import org.hibernate.mapping.Map;

import com.tierstall.client.event.GoToPageEvent;
import com.tierstall.client.event.GoToPageEventHandler;
import com.tierstall.client.event.LoginEvent;
import com.tierstall.client.event.LoginEventHandler;

import com.tierstall.client.presenter.AddTierPresenterImpl;
import com.tierstall.client.presenter.GroupMGMTPresenter;
import com.tierstall.client.presenter.SearchResultPresenter;
import com.tierstall.client.presenter.UserMGMTPresenter;
import com.tierstall.client.presenter.DBFilterPresenter;

import com.tierstall.client.presenter.LoginPresenter;
import com.tierstall.client.presenter.MainPresenter;

import com.tierstall.client.presenter.Presenter;
import com.tierstall.client.service.WebServices;

import com.tierstall.client.view.LoginView;

import com.tierstall.shared.Logger;
import com.tierstall.shared.Page;
import com.tierstall.shared.SearchQuery;
import com.tierstall.shared.UserDTO;
import com.tierstall.shared.UserType;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;

public class AppController implements Presenter, ValueChangeHandler<String> {
	private final HandlerManager eventBus;
	private final WebServices rpcServices;
	private HasWidgets container;
	private String session_id;
	private UserDTO currentUser;
	private MainPresenter mainPresenter;
	private HashMap<String, Object> stateMap;

	// private HashMap<String, Presenter> presenterMap;

	public AppController(WebServices rpcService, HandlerManager eventBus) {
		this.eventBus = eventBus;
		this.rpcServices = rpcService;
		stateMap = new HashMap<String, Object>();
		mainPresenter = new MainPresenter(rpcServices, "blalba", eventBus, this);
		// presenterMap = new HashMap<String, Presenter>();
		bind();
	}

	private void bind() {
		History.addValueChangeHandler(this);

		// Login, Session Handling
		eventBus.addHandler(GoToPageEvent.TYPE, new GoToPageEventHandler() {
			public void onGoToPageAction(GoToPageEvent event) {
				Logger.CLIENT_INFO("Go To Page: " + event.getPage().id());
				if (isPermitted(event.getPage().getSecurityLevel())) {
					if (event.getData() != null) {
						setState(event.getPage().name(), event.getData());
					}
					History.newItem(event.getPage().id());
				} else
					mainPresenter.showNotPermittedDialog();
				// History.fireCurrentHistoryState();
			}
		});

		eventBus.addHandler(LoginEvent.TYPE, new LoginEventHandler() {
			public void onLoginAction(LoginEvent event) {
				session_id = event.getSessionId();
				currentUser = event.getLoggedInUser();
				Logger.CLIENT_INFO("Logged in with id: " + session_id);
				if (event.makeCookie()) {
					makeCookie();
					Logger.CLIENT_INFO("Cookie generated");
				}
				goHomeView();
				// getLoggedInUser();
			}
		});

		// User Management Handling
	}

	public void go(final HasWidgets container) {
		this.container = container;

		// if (!"".equals(History.getToken())) {
		// History.fireCurrentHistoryState();
		// } else
		if (getSessionFromCookie() != null) { // Cookie available

			rpcServices.getRpcSessionService().checkSession(
					getSessionFromCookie(), new AsyncCallback<Boolean>() {
						@Override
						public void onSuccess(Boolean sessionValid) {
							if (sessionValid) {
								session_id = getSessionFromCookie();
								getLoggedInUser();
							} else {
								deleteCookie();
								History.newItem(Page.LOGIN.id());
							}
						}

						public void onFailure(Throwable caught) {
							// Window.alert("Error in Login-System");
							deleteCookie();
							History.newItem(Page.LOGIN.id());
						}
					});
		} else {
			History.newItem(Page.LOGIN.id());
		}
	}

	public void onValueChange(ValueChangeEvent<String> event) {
		String token = event.getValue();

		if (token != null) {
			Presenter presenter = null;
			// showcase.
			if (token.equals(Page.LOGIN.id())) {
				presenter = new LoginPresenter(rpcServices, eventBus,
						new LoginView());

			} else if (token.equals(Page.HOME.id())) {
				presenter = mainPresenter;

			} else if (token.equals(Page.DB_FILTER.id())) {
				presenter = new DBFilterPresenter(rpcServices, session_id,
						eventBus, mainPresenter, currentUser);

			} else if (token.equals(Page.SEARCH_RESULT.id())) {
				presenter = new SearchResultPresenter(rpcServices, session_id,
						eventBus, mainPresenter, currentUser,
						(SearchQuery) getState(Page.SEARCH_RESULT.name()));

			} else if (token.equals(Page.ADD_GROUP.id())) {
				presenter = new GroupMGMTPresenter(rpcServices, session_id,
						eventBus, mainPresenter, currentUser);

			} else if (token.equals(Page.ADD_TIER.id())) {
				presenter = new AddTierPresenterImpl(rpcServices, session_id,
						eventBus, mainPresenter, currentUser);

			} else if (token.equals(Page.USER_LIST.id())) {
				presenter = new UserMGMTPresenter(rpcServices, session_id,
						eventBus, mainPresenter, currentUser);

			}
			if (presenter != null) {
				presenter.go(container);
			}
		}
	}

	private void setState(String name, Object data) {
		stateMap.put(name, data);
	}

	private Object getState(String name) {
		if (stateMap.containsKey(name))
			return stateMap.get(name);
		return null;
	}

	// Helper-Methods
	private void makeCookie() {
		Date now = new Date();
		long nowLong = now.getTime();
		nowLong = nowLong + (1000 * 60 * 60 * 24); // nowLong = nowLong + (1000
													// * 60 * 60 * 24 * 7);//
													// seven days
		now.setTime(nowLong);

		Cookies.setCookie("TierstallVerwaltung", session_id, now);
	}

	private String getSessionFromCookie() {
		Logger.CLIENT_INFO("get SessionID from Cookie: "
				+ Cookies.getCookie("TierstallVerwaltung"));
		return Cookies.getCookie("TierstallVerwaltung");
	}

	private void deleteCookie() {
		Cookies.removeCookie("TierstallVerwaltung");
	}

	private void getLoggedInUser() {
		rpcServices.getRpcSessionService().getLoggedInUser(session_id,
				new AsyncCallback<UserDTO>() {
					@Override
					public void onSuccess(UserDTO user) {
						currentUser = user;
						if (user != null)
							Logger.CLIENT_INFO("currentUser set to: "
									+ (user.getUsername()));
						else
							Logger.CLIENT_INFO("currentUser set to null???");
						goHomeView();
					}

					public void onFailure(Throwable caught) {
						Window.alert("Could not get Logged-in User!");
						History.newItem(Page.LOGIN.id());
					}
				});
	}

	private void goHomeView() {

		initializeHomeView(); // buildUserInterface
		History.newItem(Page.HOME.id());
	}

	private void initializeHomeView() {
		if (currentUser != null) {
			// Logger.INFO("Gaining permissions to: "
			// + (currentUser.getUsername()));

			if (currentUser.getPermission().equals(UserType.EDITOR)) {
				// hView.setShortcuts(new MainView_Shortcuts_admin());
			} else if (currentUser.getPermission().equals(UserType.VIEWER)) {
				// hView.setShortcuts(new MainView_Shortcuts_admin());
			} else if (currentUser.getPermission().equals(UserType.ADMIN)) {
				// hView.setShortcuts(new MainView_Shortcuts_admin());
			} else if (currentUser.getPermission().equals(UserType.GUEST)) {
				// hView.setShortcuts(new MainView_Shortcuts_admin());
			}
		} else
			Logger.CLIENT_INFO("currentUser is null!!!!???");
	}

	private boolean isPermitted(int securityLevel) {
		if (securityLevel >= currentUser.getPermission().getSecurityLevel())
			return true;
		return false;
	}
}
